<?php


namespace app\repository\Websocket;


use app\Enums\CardStatus;
use app\Enums\GamesStatus;
use app\Enums\RoomStatus;
use app\model\Card;
use app\model\Games;
use app\model\OrderCard;
use app\model\GamesRecord;
use app\model\RoomDevice;
use app\model\WxUser;
use app\repository\Repository;
use app\Server\PushServer;
use Carbon\Carbon;
use process\Websocket;
use support\Cache;
use support\Db;
use const Grpc\CALL_ERROR;

class WebsocketRepository extends BaseRepository
{
    public static function get_tcp_list($ip)
    {
        $roomList =  RoomDevice::query()->get()->toArray();
        $result = [];
        foreach ($roomList as $item){
            if (in_array($item['ip'],$ip)){
                $result[] = $item;
            }
        }
        return $result;
    }

    /**
     * 查询 ip 设备是不是前台设备
     * @param $ip
     * @return array
     */
    public static function check_is_admin_Udp_sacn($ip)
    {
        $room = RoomDevice::query()->where("udp_ip", $ip)->first();
        if (!$room){
            return self::error("该设备不在系统内，请设置设备之后使用",400);
        }
        if (!$room->is_admin){
            return self::error("该设备不是前台读卡器",300);
        }
        return self::ok();
    }


    /**
     * 查询手环设备的状态
     * @param $info
     * @return array
     */
    public static function handleUdpAdminScan($info)
    {
        $c = Card::query()->where("card_no", $info)->first();
        if (!$c){
            return self::error("该手环在系统中未注册");
        }
        $card = OrderCard::query()->where("card_id", $c->id)->first();
        if (!$card){
            return self::error('该手环未绑定订单，请设置手环之后重试');
        }
        if ($card->status == CardStatus::BIND){
            return self::error('该手环绑定了其他订单，请在其他订单解绑，或结束该订单后绑定');
        }
        if ($card->status == CardStatus::FORBIDDEN){
            return self::error('该手环被禁用，您需要解除禁用后才能绑定该手环');
        }
        if ($card->is_admin){
            return self::error("超级管理员，禁止绑定");
        }
        return self::success($card);
    }

    /**
     * 处理房间读卡器返回的数据,开机排队进行游戏
     * @param $ip
     * @param $info //card_no
     */
    public static function handleRoomScanInfo($ip ,$info)
    {
        //获取card 数据
        $card = Card::query()->where("card_no", $info)->first();
        $room = RoomDevice::query()->where("udp_ip", $ip)->first();
        if (!$card){
            return self::error('该手环不在系统中，请设置手环之后重试',300,$room->toArray());
        }
        if ($card->is_admin){
           return self::success($room->toArray(),"弹出提示框",201);
        }
        $cardId = $card->id;

        //获取 card 的订单数据，判断是否还有时间进行游戏
        $orderCard = OrderCard::query()->with(['user','order'])->where("status",0)->where("card_id", $cardId)->first();
        //购买的时间
        $ownTime = $orderCard->order->production_time;
        $cardGamesIdList = GamesRecord::query()->whereBetween("created_at",[Carbon::now()->startOfDay(),Carbon::now()->endOfDay()])->select(["game_id"])->where("card_id",$cardId)->get();
        //当前使用的时间
        $useTimeSecond = Games::query()->whereBetween("created_at",[Carbon::now()->startOfDay(),Carbon::now()->endOfDay()])->whereIn("id", $cardGamesIdList->toArray())->sum("use_time");
        $useTime = round(($useTimeSecond/60),1);
        if ($ownTime < $useTime){
            return self::error("该手环使用时长已经用完，请前往前台续费",300,$room->toArray());
        }
        //校验当前房间是否正在游戏中
        if ($room->status == RoomStatus::USING ){
            return self::error("当前房间正在游戏中，请稍候",300,$room->toArray());
        }
        if ($room->status == RoomStatus::FORBIDDEN){
            return self::error("该房间当前不可用，请咨询管理员",300,$room->toArray());
        }
        //从缓存中获取预创建组队
        $cacheData = Cache::get("$ip-bind");
        if ($cacheData){
            $cacheData = json_decode($cacheData,true);
            $userList = array_column($cacheData,"user_id");
            if (!in_array($orderCard->user->id,$userList)){
                array_push($cacheData,[
                    "card_id"=>$cardId,
                    "user_id"=>$orderCard->user->id,
                    "room_id"=>$room->id,
                ]);
            }

            $array_column = array_column($cacheData, "user_id");
            $collection = WxUser::query()->whereIn("id", $array_column)->get()->toArray();
            Cache::set("$ip-bind",json_encode($cacheData),130);

            return self::success(
                [
                    "list"=>$collection,
                    "room"=>$room->toArray()
                ]
            );
        }
        //在缓存中创建预组队，缓存时间设置为 30min
        $cacheData = [
            [
                "card_id"=>$cardId,
                "user_id"=>$orderCard->user->id,
                "room_id"=>$room->id,
            ]
        ];

        $user = WxUser::query()->where("id",$orderCard->user->id)->first();
        Cache::set("$ip-bind",json_encode($cacheData),130);
        return self::success([
            "list"=>[$user],
            "room"=>$room->toArray()
        ]);
    }

    public static function openDoor($ip)
    {

    }


    public static function confirmBeginGame($ip)
    {
        $room = RoomDevice::query()->where("outside_pc_ip", $ip)->first();
        if (!$room){
            return self::error("该设备不存在系统中");
        }

        $udp_ip = $room->udp_ip;
        $var = Cache::get("$udp_ip-bind");
        $model = RoomDevice::query()->where("outside_pc_ip", $ip)->first();
        if (!$model){
            return self::error("该设备不在系统内");
        }

        if ($var){

            Db::beginTransaction();
            try {
                $now = Carbon::now();
                $cacheData = json_decode($var, true);
                $data["cacheData"] = $cacheData;
                $device_id = self::getCardNo();
                dump("car_user",$device_id);
                $game = [
                    "device_id"=>$device_id,
                    "status"=>GamesStatus::READY,
                    "begin_time"=>$now,
                ];
                $gameModel = Games::query()->create($game);
                $gameCard = [];
                foreach ($cacheData as $item){
                    $gameCard[] = [
                        "device_id" => $device_id,
                        "game_id"=>$gameModel->id,
                        "card_id"=>$item["card_id"],
                        "user_id"=>$item['user_id'],
                        "room_id"=>$item['room_id'],
                        "begin_time"=>$now
                    ];
                }
                GamesRecord::insert($gameCard);
                Db::commit();
            }catch (\Exception $exception){
                Db::rollBack();
                dump("出现异常",$exception->getMessage());
            }

            $data["card_no"] = $device_id;
            Cache::set("$udp_ip-bind",$var,300);
            return self::success([
                "card_no"=>$data["card_no"],
                "to_ip"=>$model->inside_pc_ip,
                'room'=>$room->toArray()
            ]);
        }
        return self::error("您队伍已经销毁，请重新刷新手环");

    }

    public static function userBeginGame($data)
    {
        Games::query()->create([
            "device_id"=>$data["card_no"],
            "result"=>$data["result"],
            "status"=>GamesStatus::READY,
        ]);
    }

    public static function roomTimeOut($ip)
    {
        $var = Cache::set("$ip-bind",null);
        return self::ok("操作成功");
    }

    public static function getRoomBind($ip)
    {
        $room = RoomDevice::query()->where("outside_pc_ip", $ip)->first();
        if(!$room){
            return self::error("该设备不存在系统中");
        }
        $udpIp = $room->udp_ip;
        $var = Cache::get("$udpIp-bind",null);
        $json_decode = json_decode($var, true);
        if ($json_decode){
            $userList = array_column($json_decode, "user_id");
            $collection = WxUser::query()->whereIn("id", $userList)->get();
            return self::success(["list"=>$collection->toArray(),"room"=>$room]);
        }
        return self::success([]);
    }


    public static function getCardNo()
    {
        $rand = mt_rand(0x00000000, 0xffffffff);// make sure we're not over 0xffffff, which shouldn't happen anyway
        $rand = dechex($rand & 0xffffffff);  // add zeroes in front of the generated string   //如果有0确保0在首位
        $rand = str_pad($rand, 8, '0', STR_PAD_LEFT);
        $var = Cache::get("card_no-list");
        if ($var){
            $list = json_decode($var);
            $in_array = in_array($rand, $list);
            $exists = Games::query()->where("device_id", $rand)->whereIn("status", [GamesStatus::END,GamesStatus::CANCEL])->exists();
            if ($in_array || $exists){
                $rand = self::getCardNo();
            }
            $list[] = $rand;
            //一天过期
            Cache::set('card_no-list',json_encode($list),1440);
            return $rand;
        }
        Cache::set('card_no-list',json_encode([$rand]),1440);

        return $rand;
    }

    public static function handleUserAction($device)
    {
        Db::beginTransaction();

        try {
            $now = Carbon::now();
            $game = Games::query()->with(["card"])->where("device_id", $device)->whereBetween("created_at", [Carbon::now()->startOfDay(), Carbon::now()->endOfDay()])->first();
            if($game){
                foreach ($game->card as $item){
                    $item->end_time = Carbon::now();
                    $item->save();
                }
                $game->use_time =$now->diffInSeconds (Carbon::parse($game->begin_time), true);
                $game->end_time = $now;
                $game->save();
            }
            Db::commit();
        }catch (\Exception $exception){
            Db::rollBack();
            dump("异常",$exception->getMessage());
        }
    }

    public function send($data)
    {
        $server = new PushServer();
        $server->send($data["channel"],$data["function"],$data['data'],$data['msg'],$data['code']);
        return self::ok();
    }

}